<template>
	<div class="Websocket">客户端id:{{ websocketId }}</div>
</template>
<!--vue版本客户端-->
<script>
import axios from 'axios';
import qs from 'qs';
var Cmd = {
	getCmdMsg(cmd, data, channel, sender) {
		return JSON.stringify({
			cmd: cmd, //命令，字符串
			data: data, //数据
			sender: sender, //发送者信息{websocketid,nick,pic}
			channel: channel //加入的频道（群聊）
		});
	},
	/**
	 * 主要用于心跳检测。客户端不应理睬
	 */
	ping() {
		return this.getCmdMsg('ping');
	},
	/**
	 * 打招呼
	 */
	hello(channel, sender) {
		return this.getCmdMsg('hello', null, channel, sender);
	},
	msg(data, channel, sender) {
		//发送消息
		return this.getCmdMsg('msg', data, channel, sender);
	},
	/**
	 * 上线
	 */
	online() {
		return this.getCmdMsg('online');
	},
	/**
	 * 下线
	 */
	offline() {
		return this.getCmdMsg('offline');
	}
};
export default {
	name: 'Websocket',
	props: {
		server: {
			//websocket控制器服务器
			type: String,
			default: ''
		},
		clientId: {
			//客户端id,通过这个id订阅消息，发送消息，相当于身份证或IP地址。可以在客户端指定，也可以由服务端自动生成
			type: String,
			default: ''
		},
		channel: {
			//频道,相当于群
			type: String,
			default: ''
		},
		lazy: {
			//延迟
			//频道
			type: Boolean,
			default: false
		}
	},
	data() {
		return {
			websock: null,
			websocketId: null,
			timeoutObj: null
		};
	},
	mounted() {
		if (!this.lazy) {
			this.initWebSocket();
		}
	},
	destroyed() {
		this.websock.close(); //离开路由之后断开websocket连接
	},
	methods: {
		initWebSocket() {
			//初始化
			var that = this;
			//初始化weosocket
			//const wsuri = "ws://127.0.0.1:8080";
			//首先从后端获取ws地址
			axios({
				baseURL: that.server,
				url: '/api/ws/pre-connect',
				method: 'POST',
				headers: { 'content-type': 'application/x-www-form-urlencoded' },
				data: qs.stringify({ websocketId: that.clientId })
			}).then(response => {
				var url = response.data.data.server;
				that.websocketId = response.data.data.websocketId;
				that.websock = new WebSocket(url); //创建websocket
				that.websock.onmessage = that.onmessage;
				that.websock.onopen = that.onopen;
				that.websock.onerror = that.onerror;
				that.websock.onclose = that.onclose;
			});
		},
		onopen() {
			//websocket回调函数
			//订阅频道（群）消息
			if (this.channel) {
				this.joinChannel(this.channel);
			}
			/**打开WS之后发送心跳 */
			this.sendPing();
		},
		onerror() {
			//websocket回调函数
			console.log('连接失败，重新连接', e);
			//连接建立失败重连
			clearInterval(this.timeoutObj);
			this.initWebSocket();
		},
		onmessage(e) {
			//websocket回调函数 接收到消息时候的回调函数
			//数据接收
			if (e.data) {
				var redata = JSON.parse(e.data);
				redata = typeof redata == 'string' ? JSON.parse(redata) : redata;
				//console.log(redata );
				this.$emit('onmessage', redata); //触发事件
			}
		},
		sendData(Data) {
			//websocket原生发送数据的方法
			//readyState属性返回实例对象的当前状态。共四种
			//CONNECTING：值为0，表示正在连接。
			//OPEN：值为1，表示连接成功，可以通信了。
			//CLOSING：值为2，表示连接正在关闭。
			//CLOSED：值为3，表示连接已经关闭，或者打开连接失败。
			//数据发送
			if (this.websock !== null && this.websock.readyState === 3) {
				this.websock.close();
				this.initWebSocket(); //重连
			} else if (this.websock.readyState === 1) {
				this.websock.send(Data);
			} else if (this.websock.readyState === 0) {
				setTimeout(() => {
					this.websock.send(Data);
				}, 3000);
			}
		},
		onclose(e) {
			//websocket回调函数
			//关闭
			clearInterval(this.timeoutObj);
			console.log('断开连接', e);
		},
		sendPing() {
			// 发送心跳
			clearInterval(this.timeoutObj);
			let date = new Date();
			//this.websock.send(`send heart bet to server ${date}`);
			this.timeoutObj = setInterval(() => {
				//this.websock.send(`send heart bet to server ${date}`);
				this.websock.send(Cmd.ping());
			}, 2.5 * 60 * 1000);
		},
		/**
		 * 订阅频道
		 * @param {Object} e
		 */
		joinChannel(channel) {
			var that = this;
			axios({
				baseURL: that.server,
				url: '/api/ws/join-channel',
				method: 'POST',
				headers: { 'content-type': 'application/x-www-form-urlencoded' },
				data: qs.stringify({ websocketId: that.websocketId, channel: channel })
			}).then(response => {
				//var url=response.data.server
				that.SendChannelMsg(channel, Cmd.hello(channel), false);
				console.log(`订阅频道${channel}成功`);
			});
		},
		/**
		 * 发送频道消息
		 * @param {Object} channel
		 * @param {Object} msg
		 * param {boolean} msgWrap 消息是否通过Cmd工具包装，默认通过Cmd.msg()方法包装
		 */
		SendChannelMsg(channel, msg, msgWrap = true) {
			var that = this,
				msg = msgWrap ? Cmd.msg(msg, channel, that.websocketId) : msg;
			axios({
				baseURL: that.server,
				url: '/api/ws/send-channelmsg',
				method: 'POST',
				headers: { 'content-type': 'application/x-www-form-urlencoded' },
				data: qs.stringify({ websocketId: that.websocketId, channel: channel, msg: msg })
			}).then(response => {
				//var url=response.data.server
				console.log(`给频道${channel}发送消息成功`);
			});
		},
		/**
		 * 一对一聊天消息
		 * @param {Object} receiveId 接受者ID
		 * @param {Object} msg
		 */
		SendMsg(receiveId, msg) {
			var that = this;
			axios({
				baseURL: that.server,
				url: '/api/ws/send-msg',
				method: 'POST',
				headers: { 'content-type': 'application/x-www-form-urlencoded' },
				data: qs.stringify({ senderWebsocketId: that.websocketId, receiveWebsocketId: receiveId, msg: Cmd.msg(msg, "", that.websocketId) })
			}).then(response => {
				//var url=response.data.server
				console.log(`给频道${receiveId}发送消息成功`);
			});
		},
		getClientId() {
			//获取客户端ID,默认会从服务器获取
			return this.websocketId;
		}
	}
};
</script>
<style></style>
